package Io.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class NioServer {
    public static void main(String[] args) {
        try (Selector selector = Selector.open();  // 创建一个选择器
             ServerSocketChannel serverChannel = ServerSocketChannel.open()) {  // 创建一个服务器套接字通道
        
            // 配置服务器
            serverChannel.bind(new InetSocketAddress(8082));  // 绑定服务器到指定端口
            serverChannel.configureBlocking(false);  // 设置为非阻塞模式
            serverChannel.register(selector, SelectionKey.OP_ACCEPT);  // 注册接受连接的操作接受连接（OP_ACCEPT）、读取数据（OP_READ）
            System.out.println("NIO Server started on port 8082");  // 打印服务器启动信息
            
            while (true) {
                // 阻塞等待事件就绪
                int readyChannels = selector.select();  // 选择准备好的通道
                if (readyChannels == 0) continue;  // 如果没有准备好的通道，继续循环
                
                // 处理所有就绪的事件
                Set<SelectionKey> selectedKeys = selector.selectedKeys();  // 获取准备好的键集合
                Iterator<SelectionKey> keyIterator = selectedKeys.iterator();  // 创建键迭代器
                
                while (keyIterator.hasNext()) { //.hasNext() 检查迭代器中是否还有下一个元素。
                    SelectionKey key = keyIterator.next();  // 获取下一个键
                    keyIterator.remove();  // 处理后移除键，避免重复处理
                    
                    // 根据事件类型处理
                    if (key.isAcceptable()) {//用于检查是否有新的客户端连接请求。如果有新的连接请求，服务器会接受该连接并将客户端通道注册为可读状态，以便后续处理客户端发送的数据。
                        // 处理新连接
                        ServerSocketChannel server = (ServerSocketChannel) key.channel();  // 获取服务器通道
                        SocketChannel clientChannel = server.accept();  // 接受新的客户端连接
                        clientChannel.configureBlocking(false);  // 设置客户端通道为非阻塞模式
                        clientChannel.register(selector, SelectionKey.OP_READ);  // 注册读操作
                        System.out.println("New client connected: " + clientChannel.getRemoteAddress());  // 打印客户端连接信息
                    }
                    else if (key.isReadable()) {//用于检查是否有可读的数据。如果有可读的数据，服务器会读取数据并响应客户端。
                        // 处理读事件
                        SocketChannel clientChannel = (SocketChannel) key.channel();  // 获取客户端通道
                        ByteBuffer buffer = ByteBuffer.allocate(1024);  // 分配缓冲区
                        
                        try {
                            int bytesRead = clientChannel.read(buffer);  // 从客户端读取数据
                            if (bytesRead > 0) {
                                buffer.flip();  // 准备读取缓冲区的数据
                                byte[] data = new byte[buffer.remaining()];  // 创建字节数组存储数据
                                buffer.get(data);  // 从缓冲区读取数据到字节数组
                                String request = new String(data);  // 将字节数组转换为字符串
                                System.out.println("打印接收到的数据: " + request);  // 打印接收到的数据
                                
                                // 响应客户端
                                String response = "响应字符串: " + request;  // 创建响应字符串
                                ByteBuffer responseBuffer = ByteBuffer.wrap(response.getBytes());  // 将响应字符串包装到缓冲区
                                clientChannel.write(responseBuffer);  // 向客户端写入响应
                            } else if (bytesRead == -1) {
                                // 客户端关闭连接
                                clientChannel.close();  // 关闭客户端通道
                                System.out.println("客户端断开连接: " + clientChannel.getRemoteAddress());  // 打印客户端断开信息
                            }
                        } catch (IOException e) {
                            // 处理客户端异常断开
                            key.cancel();  // 取消键
                            clientChannel.close();  // 关闭客户端通道
                            System.out.println("Client disconnected due to exception");  // 打印客户端异常断开信息
                        }
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();  // 打印异常堆栈信息
        }
    }
}
